<template>
  <view :="fv.rootProps">
    <view :class="[ns.e('mask')]" v-if="state.showContent" @click="visibleChange()"></view>
    <view :class="[ns.e('wrapper')]" @click="visibleChange">
      <view :class="[ns.e('placeholder')]" v-if="fv.showPlaceholder">{{ fv.placeholder }}</view>
      <view :class="[ns.e('selection')]">
        <view :class="[ns.e('selection-item')]" v-for="[v, item] in fv.itemList">
          <view class="text">
            <slot name="label" :="item">{{ item.label ?? item.value }}</slot>
          </view>
          <view class="iconfont icon-close" v-if="multiple" @click.stop="removeItem(v)"></view>
        </view>
        <view :class="[ns.e('selection-item')]" v-if="fv.showOptionCount">+ {{ fv.optionCount }}</view>
        <input v-model="state.searchText" :="fv.inputProps" v-if="fv.showInput"></input>
      </view>
      <view :class="[ns.e('suffix')]">
        <slot name="suffix" :="{ isArrow: fv.isArrow }">
          <view :="fv.suffixProps"></view>
        </slot>
      </view>
    </view>
    <Paging v-model="state.queryList" :="fv.pagingProps" ref="pagingRef">
      <template v-for="slotName in Object.keys($slots)" v-slot:[slotName]="scoped">
        <slot :name="slotName" :="scoped"></slot>
      </template>
    </Paging>
  </view>
</template>

<script lang="ts" setup>
import { isEmpty, useNamespace } from '@/utils'
import Select from '.'
import Paging from '@/components/paging/index.vue'
import { computed, provide, reactive, ref } from 'vue'
import { t } from '@/locale'
import { get, isObject } from 'lodash'
import { Option as OptionNamespace, Paging as PagingNamespace } from '@/components'

defineOptions({
  name: Select.name
})
const props = defineProps(Select.props)
const emits = defineEmits(Select.emits)
const ns = useNamespace(Select.name)
const state = reactive({
  showContent: false,
  options: new Map<Exclude<OptionNamespace.Props['value'], object>, OptionNamespace.Props>(),
  searchText: '',
  queryList: Array(),
  isFcous: false
})
const getValue = (v?: OptionNamespace.Props['value']) => isObject(v) ? get(v, props.valueKey!) : v
const pagingRef = ref<PagingNamespace.Instance>()
const fv = computed(() => {
  const rootProps = {
    class: [
      ns.b,
      props.disabled && 'is-disabled',
      props.fitInputWidth && 'is-fit-width',
      state.showContent && 'is-show',
      props.multiple && 'is-multiple',
      props.collapseTags && 'is-collapse-tag',
    ]
  }
  const pagingProps = <PagingNamespace.Props>{
    fixed: false,
    auto: false,
    class: [ns.e('content')],
    ...props.pagingProps,
    onTouchmove: (e: Event) => {
      e.preventDefault()
      e.stopPropagation()
    },
    onQuery: () => { }
  }
  const isValue = isEmpty(props.modelValue) || props.multiple && !(props.modelValue as any[])?.length
  const showInput = props.filterable || props.remote
  const isArrow = !props.clearable || isValue
  const suffixProps = {
    class: ['iconfont', isArrow ? 'icon-arrow-down' : 'icon-close'],
    onClick: (e: Event) => {
      if (isArrow) return
      e.stopPropagation()
      clear()
    }
  }
  const placeholder = props.placeholder ?? t('components.select.PleaseSelect')
  const showPlaceholder = isValue && !showInput
  const itemList = [...state.options.entries()]
  const optionCount = Math.max(itemList.length - 1, 0)
  const showOptionCount = props.multiple && props.collapseTags && optionCount
  const inputProps = {
    type: 'text',
    maxlength: -1,
    class: [ns.e('selection-input')],
    placeholder,
    onInput() { 
    },
    onBlur(e: Event) { 
      emits('blur', e)
    },
    onFocus(e: Event) { 
      emits('focus', e)
    },
    onClick: (e: MouseEvent) => {
      e.stopPropagation()
    }
  }
  return {
    rootProps,
    pagingProps,
    suffixProps,
    isArrow,
    placeholder,
    isValue,
    showPlaceholder,
    showInput,
    optionCount,
    showOptionCount,
    itemList: props.collapseTags ? itemList.slice(0, 1) : itemList,
    inputProps
  }
})
const provideContext: Select.ProvideContext = {
  isActive(param) {
    const equals = (mv?: typeof param.value) => {
      const v = getValue(param.value)
      const is = v === getValue(mv)

      if (is && !state.options.has(v)) state.options.set(v, param)

      return is
    }

    if (props.multiple) return [...props.modelValue as any[]].some(equals)

    return equals(props.modelValue)
  },
  change(param) {
    if (param.disabled) return
    if (this.isActive(param)) {
      if (props.multiple) return removeItem(getValue(param.value))
      return visibleChange()
    }
    const value = param.value
    if (props.multiple) {
      const list = [...props.modelValue as any[]]
      const limit = props.multipleLimit

      if (limit && list.length >= limit) return emits('exceed', param, list)

      list.push(value)
      emits('update:modelValue', list)
      emits('change', list)
      return
    }
    state.options.delete(getValue(props.modelValue))
    emits('update:modelValue', value)
    emits('change', value)
    visibleChange()
  }
}
provide(Select.provideName, provideContext)

function visibleChange() {
  state.showContent = !state.showContent

  if (state.showContent) {
    // if (fv.value.pagingProps.auto) pagingRef.value?.pagingRef?.refresh()
  } else {
    state.searchText = ''
  }

  emits('visibleChange', state.showContent)
}
function clear() {
  const value = props.multiple ? [] : undefined
  emits('update:modelValue', value)
  emits('change', value)
  emits('clear')
  state.options.clear()
}

function removeItem(v: Parameters<typeof state.options.get>[0]) {
  if (!Array.isArray(props.modelValue)) return
  const list = [...props.modelValue]
  const index = list.findIndex(o => getValue(o) === v)
  const tagItem = state.options.get(v)!

  list.splice(index, 1)[0]
  state.options.delete(v)

  emits('update:modelValue', list)
  emits('change', list)
  emits('removeItem', tagItem)
}
</script>